package com.lagou.edu.factory;

import com.lagou.edu.anno.MyAutoWired;
import com.lagou.edu.anno.MyComponent;
import com.lagou.edu.anno.MyService;
import com.lagou.edu.anno.MyTransational;
import com.lagou.edu.utils.ClassScanner;
import com.lagou.edu.utils.ConnectionUtils;
import com.lagou.edu.utils.TransactionManager;
import com.mysql.cj.util.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author 应癫
 * <p>
 * 工厂类，生产对象（使用反射技术）
 */


public class BeanFactory {

	/**
	 * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
	 * 任务二：对外提供获取实例对象的接口（根据id获取）
	 */

	private static Map<String, Object> map = new HashMap<>();  // 存储对象

	// 注解方式存储 beans
	public static void init() {
		System.out.println("开始 beans 初始化");
		try {
			// 事务支持应该算底层，因此由框架自动注入，而不是需要配置 MyComponent 手动注入，因此直接配置beans
			createBasicBean(ConnectionUtils.class);
			createBasicBean(TransactionManager.class);
			createBasicBean(ProxyFactory.class);
			// 获取要扫描的所有类
			Set<Class<?>> clazzSet = ClassScanner.getClasses("com.lagou.edu");
			Iterator<Class<?>> iterator = clazzSet.iterator();
			while (iterator.hasNext()) {
				Class<?> clazz = iterator.next();
				if (clazz.isAnnotationPresent(MyService.class) || clazz.isAnnotationPresent(MyComponent.class)) {
					String key = null;
					if (clazz.isAnnotationPresent(MyService.class)) {
						key = clazz.getAnnotation(MyService.class).value();
					} else if (clazz.isAnnotationPresent(MyComponent.class)) {
						key = clazz.getAnnotation(MyComponent.class).value();
					}
					if (StringUtils.isNullOrEmpty(key)) {
						key = clazz.getName();
					}
					Object object = clazz.newInstance();
					System.out.println("创建bean,key=" + key + ",obj=" + object);
					map.put(key, object);
				}
			}
			// 遍历是否包含注解,注意这里必须是已经在 map中才 @MyAutoWired
			Iterator<Object> autowiredIterator = map.values().iterator();
			System.out.println("开始注入属性");
			while (autowiredIterator.hasNext()) {
				Object obj = autowiredIterator.next();
				autowiredForObj(obj);
			}
			System.out.println("完成注入属性");

			//给需要动态代理的进行代理增强
			Iterator<Map.Entry<String, Object>> entryIterator = map.entrySet().iterator();
			Map.Entry<String, Object> entry = null;
			String proxyKey = null;
			Object proxyObj = null;
			while (entryIterator.hasNext()) {
				entry = entryIterator.next();
				proxyObj = entry.getValue();
				proxyKey = entry.getKey();
				Class<?> clazz = proxyObj.getClass();
				if (clazz.isAnnotationPresent(MyTransational.class)) {
					ProxyFactory proxyFactory = (ProxyFactory) getBean(ProxyFactory.class);
					proxyObj = proxyFactory.getJdkProxy(proxyObj);
					map.put(proxyKey, proxyObj);
					System.out.println("进行了动态代理增强,key=" + proxyKey + ",object=" + clazz.getName());
				}
			}
		} catch (Exception e) {
			System.out.println("出错啦！！！！" + e.getMessage());
		}
		System.out.println("完成 beans 初始化");
	}


	private static void autowiredForObj(Object obj) throws InstantiationException, IllegalAccessException {
		Class<?> clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			if (field.isAnnotationPresent(MyAutoWired.class)) {
				setField(obj, field);
			}
		}
	}

	private static void setField(Object obj, Field field) throws IllegalAccessException, InstantiationException {
		field.setAccessible(true);
		String key = field.getAnnotation(MyAutoWired.class).value();
		if (StringUtils.isNullOrEmpty(key)) {
			key = field.getType().getName();
		}
		// 判断是否这个要设置的值其实是要注入器子类
		if (getBean(key) != null) {
			field.set(obj, getBean(key));
		} else if (getBean(field.getType().getName()) != null) {
			field.set(obj, getBean(key));
		} else {
			createBasicBean(field.getType().getClass(), key);
			field.set(obj, getBean(key));
		}
		System.out.println("对象" + obj.getClass().getSimpleName() + "注入属性" + field.getName());
	}

	/**
	 * 创建 bean 实例，直接用 newInstance 创建
	 *
	 * @param clazz
	 * @return
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 */
	private static Object createBasicBean(Class clazz) throws IllegalAccessException, InstantiationException {
		return createBasicBean(clazz, clazz.getName());
	}

	private static Object createBasicBean(Class clazz, String key) throws IllegalAccessException, InstantiationException {
		if (map.get(key) == null) {
			Object object = clazz.newInstance();
			System.out.println("创建bean,key=" + key + ",obj=" + object);
			map.put(key, object);
		}
		return map.get(key);
	}

	public static Object getBean(String id) {
		if (map.containsKey(id)) {
			return map.get(id);
		}
		System.out.println("没有获取到 bean(通过id), id=" + id);
		return null;
	}


	public static Object getBean(Class type) {
		Set<Map.Entry<String, Object>> entrySet = map.entrySet();
		Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
		Map.Entry<String, Object> entry = null;
		Object obj = null;
		String key = null;
		while (iterator.hasNext()) {
			entry = iterator.next();
			obj = entry.getValue();
			key = entry.getKey();
			// 是某个类
			if (obj.getClass().equals(type)) {
				return obj;
			}
			// 是某个类的子类
			if (type.isInterface() && fromInterface(obj.getClass(), type)) {
				return obj;
			} else {
				if (obj.getClass().isAssignableFrom(type)) {
					return obj;
				}
			}
			// 可能经过动态代理加强，导致 obj 无法识别，判断 key 是否它的实现类
			try {
				Class<?> keyClass = Class.forName(key);
				if (fromInterface(keyClass, type)) {
					System.out.println("啊啊啊啊啊啊啊");
					return obj;
				}
			} catch (Exception e) {

			}
		}
		// key 是这个类
		key = type.getName();
		if (map.containsKey(key)) {
			return map.get(key);
		}
		System.out.println("没有获取到 bean(通过类型): " + type.getName());
		return null;
	}

	private static boolean fromInterface(Class<?> clazz, Class<?> interfaceClazz) {
		if (!interfaceClazz.isInterface()) {
			return false;
		}
		Class<?>[] interfaces = clazz.getInterfaces();
		if (interfaces != null) {
			for (Class<?> i : interfaces) {
				if (i.equals(interfaceClazz)) {
					return true;
				}
			}
		}
		return false;
	}
}
